use ash::{
    Device, Entry, Instance,
    ext::{debug_utils, device_fault},
    vk::{self, Extent2D, Handle},
};
use cgmath::{Deg, Euler, Matrix3, Matrix4, Quaternion, Rad, Vector3, Vector4, prelude::*};
use core::f32;
use std::{
    cmp::min, collections::HashMap, ffi::{CStr, CString}, marker::{PhantomCovariantLifetime, PhantomData, PhantomInvariantLifetime}, ops::Deref, os::raw::*, sync::{Arc, Mutex, MutexGuard}, time::*
};
use winit::{
    application::ApplicationHandler,
    dpi::PhysicalSize,
    event::{self, ElementState, Event, WindowEvent},
    event_loop::{ActiveEventLoop, ControlFlow, EventLoop, EventLoopBuilder},
    keyboard::{KeyCode, *},
    window::{Window, WindowAttributes, WindowId},
};
use pollster::FutureExt as _;

use crate::{engine::{njm_keyboard_ctrl::*, *}, tutorials::wgpu::{const_values::*, state::*}};


#[derive(Default)]
pub struct WgpuApp<'a> {
    wnd_attrs: Option<WindowAttributes>,
    state: Option<State<'a>>,
    _marker: PhantomCovariantLifetime<'a>,
}

impl<'a> WgpuApp<'a> {

    pub fn get_wnd_attrs(&self) -> Option<WindowAttributes> {
        return self.wnd_attrs.clone();
    }

    pub fn set_wnd_attrs(&mut self, base: WindowAttributes) {
        let tmp: WindowAttributes = base
            .with_inner_size(PhysicalSize::new(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT))
            .with_title(DEFAULT_WINDOW_TITLE);
        self.wnd_attrs = Some(tmp);
    }

    pub fn close(&mut self) {
        println!("app::close");
    }

    pub fn handle_keyboard_input(
        &mut self,
        event_loop: &ActiveEventLoop,
        window_id: WindowId,
        device_id: winit::event::DeviceId,
        event: winit::event::KeyEvent,
        is_synthetic: bool,
    ) {
        println!("app::handle_keyboard_input");
        match event.physical_key {           
            PhysicalKey::Code(key_code) => {
                if KeyCode::Escape == key_code {
                    println!("ESCAPE KEY pressed, stopping");
                    self.close();
                    event_loop.exit();
                    return;
                }
                if KEY_SET_MOVEMENT.contains(&key_code) {
                    let state_ref = self.state.as_mut().unwrap();
                    let process_finished = state_ref.input_keyboard_event(&key_code, &event.state);
                    return;
                }
            }
            PhysicalKey::Unidentified(native_key_code) => {}
        }
    }

    pub fn handle_mouse_input(
        &mut self,
        event_loop: &ActiveEventLoop,
        window_id: WindowId,
        device_id: winit::event::DeviceId,
        state: winit::event::ElementState,
        button: winit::event::MouseButton,
    ) {
        println!("app::handle_mouse_input");
        if state.is_pressed() && button == event::MouseButton::Left {
            println!("left mouse button clicker!");
        }
    }

    pub fn redraw(&mut self, event_loop: &ActiveEventLoop, window_id: WindowId) {
        println!("app::redraw");
        let state_ref = self.state.as_mut().unwrap();
        if window_id == state_ref.window.id() {
            state_ref.update();
            match state_ref.render() {
                Ok(_) => {}
                // 如果发生上下文丢失，就重新配置 surface
                Err(wgpu::SurfaceError::Lost) => state_ref.resize(state_ref.size),
                // 系统内存不足，此时应该退出
                Err(wgpu::SurfaceError::OutOfMemory) => {
                    eprintln!("wgpu::SurfaceError::OutOfMemory, closing app");
                    self.close();
                    event_loop.exit();
                    return;
                },
                // 所有其他错误（如过时、超时等）都应在下一帧解决
                Err(e) => eprintln!("{:?}", e),
            }
            state_ref.window.request_redraw();
        }    
    }

    pub fn resume(&mut self, event_loop: &ActiveEventLoop) {
        println!("app::resume");
        let attrs: WindowAttributes = if self.wnd_attrs.is_some() {
            self.wnd_attrs.as_ref().unwrap().clone()
        } else {
            let attri = WindowAttributes::default();
            self.wnd_attrs = Some(attri.clone());
            attri
        };
        // let wnd_sz = self
        //     .wnd_attrs
        //     .as_ref()
        //     .unwrap()
        //     .inner_size
        //     .unwrap()
        //     .to_physical::<u32>(1.0);
        self.state = Some(State::new(event_loop, attrs).block_on());
    }

    pub fn resize(&mut self, size: PhysicalSize<u32>) {
        println!("app::resize: width: {} , height: {}", size.width, size.height);
        if size.width == 0 || size.height == 0 {return;}
        let attrs = self.wnd_attrs.as_ref().unwrap().clone().with_inner_size(size);
        self.wnd_attrs = Some(attrs);
        self.state.as_mut().unwrap().resize(size);
    }

    pub fn refactor(&mut self, scale_factor: f64, mut inner_size_writer: winit::event::InnerSizeWriter) {
        println!("app::refactor: factor: {}", scale_factor);
        let current_size: PhysicalSize<u32> = self.wnd_attrs.as_ref().unwrap().inner_size.unwrap().to_physical::<u32>(1.0);
        let new_inner_size: PhysicalSize<u32> = PhysicalSize { 
            width: (current_size.width as f64 * scale_factor), 
            height: (current_size.height as f64 * scale_factor),
        }.cast();
        let _ = inner_size_writer.request_inner_size(new_inner_size).unwrap();
    }

}

impl ApplicationHandler for WgpuApp<'_> {

    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
        println!("ApplicationHandler::resumed");
        self.resume(event_loop);
    }

    fn window_event(
            &mut self,
            event_loop: &ActiveEventLoop,
            window_id: WindowId,
            event: WindowEvent,
        ) {
        match event {
            WindowEvent::CloseRequested => {
                println!("close button pressed");
                self.close();
                event_loop.exit();
            }
            WindowEvent::RedrawRequested => {
                println!("ApplicationHandler::WindowEvent::RedrawRequested");
                self.redraw(event_loop, window_id); // rendering                 
            }
            WindowEvent::Resized(size) => {                               
                self.resize(size);
            }
            WindowEvent::KeyboardInput {
                device_id,
                event,
                is_synthetic,
            } => {
                self.handle_keyboard_input(event_loop, window_id, device_id, event, is_synthetic);
            }
            WindowEvent::MouseInput {
                device_id,
                state,
                button,
            } => {
                self.handle_mouse_input(event_loop, window_id, device_id, state, button);
            }
            WindowEvent::ScaleFactorChanged { 
                scale_factor, 
                inner_size_writer 
            } => {
                self.refactor(scale_factor, inner_size_writer);
            }
            _ => (),
        }
    }
    
    fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: event::StartCause) {
        let _ = (event_loop, cause);
    }
    
    fn user_event(&mut self, event_loop: &ActiveEventLoop, event: ()) {
        let _ = (event_loop, event);
    }
    
    fn device_event(
        &mut self,
        event_loop: &ActiveEventLoop,
        device_id: event::DeviceId,
        event: event::DeviceEvent,
    ) {
        let _ = (event_loop, device_id, event);
    }
    
    fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
        let _ = event_loop;
    }
    
    fn suspended(&mut self, event_loop: &ActiveEventLoop) {
        let _ = event_loop;
    }
    
    fn exiting(&mut self, event_loop: &ActiveEventLoop) {
        let _ = event_loop;
    }
    
    fn memory_warning(&mut self, event_loop: &ActiveEventLoop) {
        let _ = event_loop;
    }

}